﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.ServiceModel.Syndication;
using System.Text;
using System.Xml;
using System.Xml.Xsl;

namespace Klinkby.PodCaster.Model
{
    [Serializable]
    sealed class Feed : IFeed
    {
        Feed(string title, Uri url, IEnumerable<IPost> posts)        
        {
            Title = title;
            Url = url;
            Posts = posts;
        }

        public static Feed FromUrl(Uri url)
        {
            var sff = new Rss20FeedFormatter();
            Http.Get(url, responseSteam => Deserialize(responseSteam, sff));
            return new Feed(
                sff.Feed.Title.Text,
                url,
                sff.Feed.Items
                        .Select(item => (IPost)new Post(item.Title.Text,
                                                        item.Links
                                                            .Where(link => link.RelationshipType == "enclosure")
                                                            .Select(link => link.Uri)
                                                            .ToArray()))
                        .ToArray()
                );
        }

        private static void Deserialize(Stream stream, Rss20FeedFormatter sff)
        {
            using (var rd = XmlReader.Create(
                stream,
                new XmlReaderSettings()
                {
                    ProhibitDtd = false,
                    IgnoreComments = true,
                    IgnoreProcessingInstructions = true,
                    IgnoreWhitespace = true,
                    CheckCharacters = true,
                    CloseInput = true,
                }))
            {
                // https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=325421
                using (var ms = new MemoryStream())
                {
                    using (var wr = XmlWriter.Create(ms))
                        Sanitize(rd, wr);
                    ms.Flush();
                    ms.Seek(0, SeekOrigin.Begin);
                    using (var rd2 = XmlReader.Create(ms, rd.Settings))
                    {
                        sff.ReadFrom(rd2);
                    }
                }
            }
        }

        readonly static XslCompiledTransform _xslt = new Func<XslCompiledTransform>(() => {
            var xslt = new XslCompiledTransform();
            using(var txtRd = new StringReader(Properties.Resources.FeedSanitizer))
            using(var rd = XmlReader.Create(txtRd))
            xslt.Load(rd);
            return xslt;
        })();

        static void Sanitize(XmlReader reader, XmlWriter writer)
        {
            _xslt.Transform(reader, writer);
        }
       
        #region IFeed Members

        public string Title
        {
            get;
            private set;
        }

        public Uri Url
        {
            get;
            private set;
        }

        public IEnumerable<IPost> Posts
        {
            get;
            private set;
        }

        public DateTime Refreshed
        {
            get;
            private set;
        }

        public void Refresh()
        {
            Feed newFeed = Feed.FromUrl(Url);
            Title = newFeed.Title;
            Posts = newFeed.Posts
                           .Select(newPost => Posts.FirstOrDefault(p => p.Title == newPost.Title) ?? newPost)
                           .ToArray();
            Refreshed = DateTime.Now;
        }

        public string GetLocalDir()
        { 
            string dir = Title;
            int i;
            while ((i = dir.IndexOfAny(Path.GetInvalidPathChars())) >= 0)
                dir.Remove(i, 1);
            return Path.Combine(Environment.CurrentDirectory, dir);            
        }

        #endregion
    }
}
